﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Collections;
using System.Security;

namespace Djs.Neuronic.Core
{
    #region CollectIdx<T> kolekce dat s dvojitým indexem podle item.Id a item.Key
    /// <summary>
    /// Kolekce dat s dvojitým indexem podle int item.Id a string item.Key.
    /// Hodnota klíče string Key je case-insensitive.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CollectIdx<T> : IEnumerable<T>, IDisposable where T : IIdKey
    {
        #region Konstrukce
        public CollectIdx()
        {
            this.DisableKeyLogic = false;
            this.DataId = new DictionaryEvnt<int, T>();
            this.DataKey = new DictionaryEvnt<string, T>();
        }
        /// <summary>
        /// Konstruktor.
        /// Umožní zakázat tvorbu indexu podle string Key, když chceme povolit více shodných Key.
        /// Pak nelze podle Key vyhledávat.
        /// </summary>
        /// <param name="disableKeyLogic">Zákaz indexování podle string Key</param>
        public CollectIdx(bool disableKeyLogic)
        {
            this.DisableKeyLogic = disableKeyLogic;
            this.DataId = new DictionaryEvnt<int, T>();
            if (!disableKeyLogic)
                this.DataKey = new DictionaryEvnt<string, T>();
        }
        public override string ToString()
        {
            return "Collection of types:" + typeof(T).Name + "; ItemCount=" + this.DataId.Count + "; KeyCount=" + (DisableKeyLogic ? "disabled" : this.DataKey.Count.ToString());
        }
        /// <summary>
        /// Zákaz indexování podle string Key. Nastavit lze pouze v konstruktoru.
        /// </summary>
        public bool DisableKeyLogic { get; protected set; }
        /// <summary>
        /// Hlavní Dictionary, obsahuje všechny položky, dle int Id
        /// </summary>
        protected DictionaryEvnt<int, T> DataId { get; private set; }
        /// <summary>
        /// Vedlejší Dictinary, obsahuje pouze ty položky, které mají string Key.
        /// Používá se jen tehdy, pokud není zakázaná Key logika (this.DisableKeyLogic).
        /// </summary>
        protected DictionaryEvnt<string, T> DataKey { get; private set; }
        #endregion
        #region Imitace Dictionary a Listu
        /// <summary>
        /// Počet vět
        /// </summary>
        public int Count { get { return this.DataId.Count; } }
        /// <summary>
        /// Přidá větu
        /// </summary>
        /// <param name="value"></param>
        public void Add(T value)
        {
            this.DataId.Add(value.Id, value);
            string k = FormatThisKey(value.Key);
            if (!String.IsNullOrEmpty(k))
                this.DataKey.Add(k, value);
        }
        /// <summary>
        /// Přidá řadu vět
        /// </summary>
        /// <param name="values"></param>
        public void Add(params T[] values)
        {
            foreach (T value in values)
                this.Add(value);
        }
        /// <summary>
        /// Přidá pole vět
        /// </summary>
        /// <param name="list"></param>
        public void AddRange(IEnumerable<T> list)
        {
            foreach (T value in list)
                this.Add(value);
        }
        /// <summary>
        /// Test, zda kolekce již obsahuje větu (podle klíče Id)
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool ContainsKey(T value)
        {
            return this.DataId.ContainsKey(value.Id);
        }
        /// <summary>
        /// Test, zda kolekce již obsahuje větu (podle klíče Id)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool ContainsKey(int id)
        {
            return this.DataId.ContainsKey(id);
        }
        /// <summary>
        /// Test, zda kolekce již obsahuje větu (podle klíče Key)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(string key)
        {
            string k = FormatThisKey(key);
            if (k == null) return false;
            return this.DataKey.ContainsKey(k);
        }
        /// <summary>
        /// Zkusí najít větu podle klíče Id
        /// </summary>
        /// <param name="id"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValue(int id, out T value)
        {
            return this.DataId.TryGetValue(id, out value);
        }
        /// <summary>
        /// Zkusí najít větu podle klíče Key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValue(string key, out T value)
        {
            string k = FormatThisKey(key);
            if (k == null)
            {
                value = default(T);
                return false;
            }
            return this.DataKey.TryGetValue(k, out value);
        }
        /// <summary>
        /// Vrátí větu podle klíče Id.
        /// Pokud neexistuje, vyhodí chybu.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T this[int id]
        {
            get { return this.DataId[id]; }
        }
        /// <summary>
        /// Vrátí větu podle klíče Key.
        /// Pokud neexistuje, vyhodí chybu.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T this[string key]
        {
            get
            {
                string k = FormatThisKey(key);
                if (k == null) return default(T);
                return this.DataKey[k];
            }
        }
        /// <summary>
        /// Odebere větu podle klíče Id
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Remove(T value)
        {
            return this.Remove(value.Id);
        }
        /// <summary>
        /// Odebere větu podle klíče Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Remove(int id)
        {
            T value;
            if (this.TryGetValue(id, out value))
            {
                this.DataId.Remove(id);
                if (!String.IsNullOrEmpty(value.Key) && this.DataKey.ContainsKey(value.Key))
                    this.DataKey.Remove(value.Key);
                return true;
            }
            return false;
        }
        /// <summary>
        /// Odebere větu podle klíče Key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Remove(string key)
        {
            string k = FormatThisKey(key);
            T value;
            if (!String.IsNullOrEmpty(k) && this.DataKey.TryGetValue(k, out value))
            {
                this.DataKey.Remove(k);
                if (this.DataId.ContainsKey(value.Id))
                    this.DataId.Remove(value.Id);
                return true;
            }
            return false;
        }
        /// <summary>
        /// Vyprázdní celou kolekci
        /// </summary>
        public void Clear()
        {
            this.DataId.Clear();
            if (!this.DisableKeyLogic)
                this.DataKey.Clear();
        }
        #endregion
        #region Přidané funkce
        /// <summary>
        /// Vrátí seznam položek, netříděný (v pořadí přidávání).
        /// Seznam je nově vytvořený objekt, který není závislý na interních datech CollectIdx.
        /// </summary>
        public List<T> List
        {
            get
            {
                List<T> result = new List<T>(this.DataId.Values);
                return result;
            }
        }
        /// <summary>
        /// Vrátí seznam položek, tříděný dle hodnoty Key
        /// </summary>
        public List<T> SortedList
        {
            get
            {
                List<T> result = new List<T>(this.DataId.Values);
                result.Sort(delegate(T a, T b) { return String.Compare(a.Key, b.Key, true); });
                return result;
            }
        }
        /// <summary>
        /// Formátuje klíč (vrací null, anebo key.Trim().ToLower();)
        /// Vrací null, pokud je zakázaná logika Key (DisableKeyLogic je true).
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected string FormatThisKey(string key)
        {
            if (this.DisableKeyLogic) return null;
            if (string.IsNullOrEmpty(key)) return null;
            return key.Trim().ToLower();
        }
        /// <summary>
        /// Formátuje klíč (vrací null, anebo key.Trim().ToLower();)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string FormatKey(string key)
        {
            if (string.IsNullOrEmpty(key))
                return null;
            return key.Trim().ToLower();
        }
        #endregion
        #region IEnumerable<T> + IEnumerable Members. Dovolí snadno enumerovat seznamem.
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return this.DataId.Values.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.DataId.Values.GetEnumerator();
        }
        public void Dispose()
        {
            this.Clear();
        }
        void IDisposable.Dispose()
        {
            this.Dispose();
        }
        #endregion
    }
    #endregion
    #region Interface, který garantuje přítomnost property int Id a string Key.
    /// <summary>
    /// Interface, který garantuje přítomnost property int Id a string Key.
    /// Používá se pro objekty, které mohou být ukládány do dvojindexové kolekce CollectIdx.
    /// </summary>
    public interface IIdKey
    {
        int Id { get; }
        string Key { get; }
    }
    #endregion
    #region DictionaryEvnt která poskytuje eventy při změnách
    /// <summary>
    /// DictionaryEvnt : adaptér na Dictionary.
    /// Poskytuje eventy při změnách.
    /// Obsahuje neviditelnou cache na poslední nalezenou hodnotu - pro urychlení opakovaného hledání téhož klíče.
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public class DictionaryEvnt<TKey, TValue> : IEnumerable<TValue>, IEnumerable
    {
        #region Konstrukce
        protected Dictionary<TKey, TValue> Dict;
        public override string ToString()
        {
            return "DictionaryEvnt<" + typeof(TKey).GetType().Name + ", " + typeof(TValue).GetType().Name + ">; ItemCount=" + this.Dict.Count.ToString();
        }
        #endregion
        #region Eventy
        public class DictionaryEventArgs : EventArgs
        {
            /// <summary>
            /// Data, o která se jedná
            /// </summary>
            public KeyValuePair<TKey, TValue> KeyValue { get; protected set; }
            /// <summary>
            /// Eventhandler může zakázat operaci
            /// </summary>
            public bool Cancel { get; set; }
        }
        /// <summary>
        /// Předpis pro metodu, která je event handlerem změn v DictionaryEvnt
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public delegate void DictionaryEventHandler(object sender, DictionaryEventArgs args);
        /// <summary>
        /// Event volaný před přidáním nové položky. 
        /// Handler může přidání zakázat. Pak se položka tiše nepřidá. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemAddBefore;
        /// <summary>
        /// Event volaný před vrácením nalezené položky. 
        /// Handler může vrácení položky zakázat. Pak se položka nevrátí, jako by se nenašla. V metodě this[] get dojde k výjimce Key not exists. V metodě TryGetValue se vrátí false.
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemGetBefore;
        /// <summary>
        /// Event volaný před vložením existující položky v metodě this[] set. 
        /// Handler může vložení zakázat. Pak se položka tiše nevloží. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemSetBefore;
        /// <summary>
        /// Event volaný před smazáním existující položky. 
        /// Handler může smazání zakázat. Pak se položka tiše nesmaže. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemRemoveBefore;
        #endregion
        #region Neviditelná cache na LastFind položku
        /// <summary>
        /// Cache: reset (po provedení změny v Dictionary.Key = po metodě Add, Remove, Clear).
        /// </summary>
        protected void LastValueReset()
        {
            this.LastExists = false;
            this.LastKey = default(TKey);
            this.LastFound = false;
            this.LastValue = default(TValue);
        }
        /// <summary>
        /// Cache: data existují, jsou uložena a platná
        /// </summary>
        protected bool LastExists;
        /// <summary>
        /// Cache: Klíč posledně hledané položky. Informace o tom, zda byla nalezena je v this.LastFind, nalezená hodnota je v this.LastValue
        /// </summary>
        protected TKey LastKey;
        /// <summary>
        /// Cache: Výsledek posledního hledání klíče this.LastKey
        /// </summary>
        protected bool LastFound;
        /// <summary>
        /// Cache: Posledně nalezená položka (=data) dle klíče LastKey
        /// </summary>
        protected TValue LastValue;
        /// <summary>
        /// Detekce: hledali jsme posledně danou hodnotu? Neřeším s jakým výsledkem (ten je v this.LastFind, hodnota je v this.LastValue).
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected bool LastValueIsForKey(TKey key)
        {
            if (key == null) return false;
            return (this.LastExists && key.Equals(this.LastKey));
        }
        /// <summary>
        /// Detekce: máme v cache nalezenou hodnotu pro hledání daného klíče?
        /// Tzn. posledně jsme hledali tentýž klíč, a data jsme našli. Můžeme vrátit LastValue.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected bool LastValueIsFindForKey(TKey key)
        {
            return (this.LastExists && key.Equals(this.LastKey) && this.LastFound);
        }
        /// <summary>
        /// Cache: uloží si hledaný klíč, výsledek a hodnotu pro příští hledání
        /// </summary>
        /// <param name="key"></param>
        /// <param name="found"></param>
        /// <param name="value"></param>
        protected void LastValueSet(TKey key, bool found, TValue value)
        {
            this.LastExists = true;
            this.LastKey = key;
            this.LastFound = found;
            this.LastValue = value;
        }
        #endregion
        #region Dictionary : přechodníky metod a property z this do this.Dict. Třída this se zvenku tváří jako Dictionary.
        /// Summary:
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the default initial capacity, and uses the default
        ///     equality comparer for the key type.
        public DictionaryEvnt()
        {
            this.Dict = new Dictionary<TKey, TValue>();
            this.LastValueReset();
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>
        ///     and uses the default equality comparer for the key type.
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     dictionary is null.
        ///
        ///   System.ArgumentException:
        ///     dictionary contains one or more duplicate keys.
        /// </summary>
        public DictionaryEvnt(IDictionary<TKey, TValue> dictionary)
        {
            this.Dict = new Dictionary<TKey, TValue>(dictionary);
            this.LastValueReset();
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the default initial capacity, and uses the specified
        ///     System.Collections.Generic.IEqualityComparer<T>.
        ///
        /// Parameters:
        ///   comparer:
        ///     The System.Collections.Generic.IEqualityComparer<T> implementation to use
        ///     when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
        ///     for the type of the key.
        /// </summary>
        public DictionaryEvnt(IEqualityComparer<TKey> comparer)
        {
            this.Dict = new Dictionary<TKey, TValue>(comparer);
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the specified initial capacity, and uses the default
        ///     equality comparer for the key type.
        ///
        /// Parameters:
        ///   capacity:
        ///     The initial number of elements that the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     can contain.
        ///
        /// Exceptions:
        ///   System.ArgumentOutOfRangeException:
        ///     capacity is less than 0.
        /// </summary>
        public DictionaryEvnt(int capacity)
        {
            this.Dict = new Dictionary<TKey, TValue>(capacity);
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>
        ///     and uses the specified System.Collections.Generic.IEqualityComparer<T>.
        ///
        /// Parameters:
        ///   dictionary:
        ///     The System.Collections.Generic.IDictionary<TKey,TValue> whose elements are
        ///     copied to the new System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        ///   comparer:
        ///     The System.Collections.Generic.IEqualityComparer<T> implementation to use
        ///     when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
        ///     for the type of the key.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     dictionary is null.
        ///
        ///   System.ArgumentException:
        ///     dictionary contains one or more duplicate keys.
        /// </summary>
        public DictionaryEvnt(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        {
            this.Dict = new Dictionary<TKey, TValue>(dictionary, comparer);
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the specified initial capacity, and uses the specified
        ///     System.Collections.Generic.IEqualityComparer<T>.
        ///
        /// Parameters:
        ///   capacity:
        ///     The initial number of elements that the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     can contain.
        ///
        ///   comparer:
        ///     The System.Collections.Generic.IEqualityComparer<T> implementation to use
        ///     when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
        ///     for the type of the key.
        ///
        /// Exceptions:
        ///   System.ArgumentOutOfRangeException:
        ///     capacity is less than 0.
        /// </summary>
        public DictionaryEvnt(int capacity, IEqualityComparer<TKey> comparer)
        {
            this.Dict = new Dictionary<TKey, TValue>(comparer);
        }
        /// <summary>
        ///     Gets the System.Collections.Generic.IEqualityComparer<T> that is used to
        ///     determine equality of keys for the dictionary.
        ///
        /// Returns:
        ///     The System.Collections.Generic.IEqualityComparer<T> generic interface implementation
        ///     that is used to determine equality of keys for the current System.Collections.Generic.Dictionary<TKey,TValue>
        ///     and to provide hash values for the keys.
        /// </summary>
        public IEqualityComparer<TKey> Comparer
        { get { return this.Dict.Comparer; } }
        /// <summary>
        ///     Gets the number of key/value pairs contained in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     The number of key/value pairs contained in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public int Count
        { get { return this.Dict.Count; } }
        /// <summary>
        ///     Gets a collection containing the keys in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     A System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection containing
        ///     the keys in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public Dictionary<TKey, TValue>.KeyCollection Keys
        { get { return this.Dict.Keys; } }
        /// <summary>
        ///     Gets a collection containing the values in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     A System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection containing
        ///     the values in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public Dictionary<TKey, TValue>.ValueCollection Values
        { get { return this.Dict.Values; } }
        /// <summary>
        ///     Gets or sets the value associated with the specified key.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the value to get or set.
        ///
        /// Returns:
        ///     The value associated with the specified key. If the specified key is not
        ///     found, a get operation throws a System.Collections.Generic.KeyNotFoundException,
        ///     and a set operation creates a new element with the specified key.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        ///
        ///   System.Collections.Generic.KeyNotFoundException:
        ///     The property is retrieved and key does not exist in the collection.
        /// </summary>
        public TValue this[TKey key]
        {
            get
            {
                if (this.LastValueIsForKey(key))
                {   // Cache:
                    if (this.LastFound) return this.LastValue;
                    // Chyba:
                    throw new KeyNotFoundException("Key " + key.ToString() + " not found in DictionaryEvnt.");
                }
                TValue value;
                bool found = this.Dict.TryGetValue(key, out value);
                this.LastValueSet(key, found, value);
                if (found) return value;
                throw new KeyNotFoundException("Key " + key.ToString() + " not found in DictionaryEvnt.");
            }
            set
            {
                this.Dict[key] = value;
                this.LastValueReset();
            }
        }
        /// <summary>
        ///     Adds the specified key and value to the dictionary.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the element to add.
        ///
        ///   value:
        ///     The value of the element to add. The value can be null for reference types.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        ///
        ///   System.ArgumentException:
        ///     An element with the same key already exists in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public void Add(TKey key, TValue value)
        {
            this.Dict.Add(key, value);

            if (this.LastValueIsForKey(key))
                this.LastValueReset();
        }
        /// <summary>
        ///     Removes all keys and values from the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public void Clear()
        {
            this.Dict.Clear();
            this.LastValueReset();
        }
        /// <summary>
        ///     Determines whether the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     contains the specified key.
        ///
        /// Parameters:
        ///   key:
        ///     The key to locate in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
        ///     element with the specified key; otherwise, false.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        /// </summary>
        public bool ContainsKey(TKey key)
        {
            if (this.LastValueIsForKey(key))
            {   // Cache:
                return this.LastFound;
            }
            TValue value;
            bool found = this.Dict.TryGetValue(key, out value);
            this.LastValueSet(key, found, value);
            return found;
        }
        /// <summary>
        ///     Determines whether the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     contains a specific value.
        ///
        /// Parameters:
        ///   value:
        ///     The value to locate in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///     The value can be null for reference types.
        ///
        /// Returns:
        ///     true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
        ///     element with the specified value; otherwise, false.
        /// </summary>
        public bool ContainsValue(TValue value)
        {
            return this.Dict.ContainsValue(value);
        }
        /// <summary>
        ///     Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     A System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator structure
        ///     for the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
        {
            return this.Dict.GetEnumerator();
        }
        /// <summary>
        ///     Implements the System.Runtime.Serialization.ISerializable interface and returns
        ///     the data needed to serialize the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     instance.
        ///
        /// Parameters:
        ///   info:
        ///     A System.Runtime.Serialization.SerializationInfo object that contains the
        ///     information required to serialize the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     instance.
        ///
        ///   context:
        ///     A System.Runtime.Serialization.StreamingContext structure that contains the
        ///     source and destination of the serialized stream associated with the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     instance.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     info is null.
        /// </summary>
        [SecurityCritical]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            this.Dict.GetObjectData(info, context);
        }
        /// <summary>
        ///     Implements the System.Runtime.Serialization.ISerializable interface and raises
        ///     the deserialization event when the deserialization is complete.
        ///
        /// Parameters:
        ///   sender:
        ///     The source of the deserialization event.
        ///
        /// Exceptions:
        ///   System.Runtime.Serialization.SerializationException:
        ///     The System.Runtime.Serialization.SerializationInfo object associated with
        ///     the current System.Collections.Generic.Dictionary<TKey,TValue> instance is
        ///     invalid.
        /// </summary>
        public virtual void OnDeserialization(object sender)
        { }
        /// <summary>
        ///     Removes the value with the specified key from the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the element to remove.
        ///
        /// Returns:
        ///     true if the element is successfully found and removed; otherwise, false.
        ///     This method returns false if key is not found in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        /// </summary>
        public bool Remove(TKey key)
        {
            if (this.LastValueIsForKey(key))
                this.LastValueReset();

            return this.Dict.Remove(key);
        }
        /// <summary>
        ///     Gets the value associated with the specified key.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the value to get.
        ///
        ///   value:
        ///     When this method returns, contains the value associated with the specified
        ///     key, if the key is found; otherwise, the default value for the type of the
        ///     value parameter. This parameter is passed uninitialized.
        ///
        /// Returns:
        ///     true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
        ///     element with the specified key; otherwise, false.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        /// </summary>
        public bool TryGetValue(TKey key, out TValue value)
        {
            if (this.LastValueIsForKey(key))
            {   // Cache:
                value = this.LastValue;
                return this.LastFound;
            }
            bool found = this.Dict.TryGetValue(key, out value);
            this.LastValueSet(key, found, value);
            return found;
        }
        #endregion
        #region IEnumerable, IEnumerable<TValue> Members Members
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.Dict.Values.GetEnumerator();
        }
        IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
        {
            return this.Dict.Values.GetEnumerator();
        }
        #endregion
    }
    #endregion
}
